package com.gitee.melin.bee.core.jdbc.dialect.impl;

import com.gitee.melin.bee.core.jdbc.QueryResult;
import com.gitee.melin.bee.core.jdbc.dialect.JdbcDialect;
import com.gitee.melin.bee.core.jdbc.enums.DataSourceType;
import com.gitee.melin.bee.core.jdbc.relational.*;
import com.google.common.collect.Lists;
import com.mongodb.ConnectionString;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoCollection;
import com.mongodb.connection.ClusterDescription;
import java.sql.Statement;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import org.apache.commons.lang3.StringUtils;
import org.bson.Document;

public class MongodbJdbcDialect implements JdbcDialect {

    private ConnectionInfo connectionInfo;

    private MongoClient mongoClient;

    public MongodbJdbcDialect(ConnectionInfo connectionInfo) {
        if (connectionInfo == null) {
            return;
        }

        this.connectionInfo = connectionInfo;
        String url = connectionInfo.getUrl();
        if (!StringUtils.contains(url, '@')) {
            url = StringUtils.replace(
                    url, "://", "://" + connectionInfo.getUsername() + ":" + connectionInfo.getPassword() + "@");
        }

        ConnectionString connectionString = new ConnectionString(url);
        mongoClient = MongoClients.create(connectionString);
    }

    @Override
    public DataSourceType getDataSourceType() {
        return DataSourceType.MONGODB;
    }

    @Override
    public MetaDataSource testConnection(ConnectionInfo connectionInfo) {
        String url = connectionInfo.getUrl();
        if (!StringUtils.contains(url, '@')) {
            url = StringUtils.replace(
                    url, "://", "://" + connectionInfo.getUsername() + ":" + connectionInfo.getPassword() + "@");
        }
        ConnectionString connectionString = new ConnectionString(url);
        MongoClient mongoClient = MongoClients.create(connectionString);
        ClusterDescription description = mongoClient.getClusterDescription();

        return new MetaDataSource();
    }

    @Override
    public DatabaseVersion getDatabaseVersion() {
        throw new UnsupportedOperationException();
    }

    @Override
    public List<String> getDatabases() {
        List<String> databases = Lists.newArrayList();
        for (String name : mongoClient.listDatabaseNames()) {
            databases.add(name);
        }
        return databases;
    }

    @Override
    public List<String> getSchemas() {
        return this.getDatabases();
    }

    @Override
    public MetaTable getSchemaTable(String schemaName, String tableName, boolean containColumn) {
        throw new UnsupportedOperationException();
    }

    @Override
    public List<String> getTableNames(String schemaName) {
        List<String> tables = Lists.newArrayList();
        for (String name : mongoClient.getDatabase(schemaName).listCollectionNames()) {
            tables.add(name);
        }
        return tables;
    }

    @Override
    public List<SimpleMetaTable> getSimpleTables(String schemaName) {
        List<SimpleMetaTable> tables = Lists.newArrayList();
        for (Document document : mongoClient.getDatabase(schemaName).listCollections()) {
            SimpleMetaTable table = new SimpleMetaTable();
            table.setTableName(document.getString("name"));
            table.setTableType(BeeTableType.TABLE);
            tables.add(table);
        }
        return tables;
    }

    @Override
    public List<MetaTable> getSchemaTables(String schemaName) {
        List<MetaTable> tables = Lists.newArrayList();
        for (Document document : mongoClient.getDatabase(schemaName).listCollections()) {
            MetaTable table = new MetaTable();
            table.setTableName(document.getString("name"));
            table.setTableType(BeeTableType.TABLE);
            tables.add(table);
        }
        return tables;
    }

    @Override
    public LinkedHashSet<String> getPrimaryKeys(String schemaName, String tableName) {
        throw new UnsupportedOperationException();
    }

    @Override
    public List<MetaColumn> getSchemaColumns(String schemaName, String tableName) {
        List<MetaColumn> columns = Lists.newArrayList();
        MongoCollection<Document> collection =
                mongoClient.getDatabase(schemaName).getCollection(tableName);
        return columns;
    }

    @Override
    public String getCreateTableScript(BeeTableType type, String schemaName, String tableName) {
        throw new UnsupportedOperationException();
    }

    @Override
    public Statement getQueryStatement() {
        throw new UnsupportedOperationException();
    }

    @Override
    public CompletableFuture<QueryResult> asyncQuery(String sql) {
        throw new UnsupportedOperationException();
    }

    @Override
    public CompletableFuture<QueryResult> asyncQuery(String schema, String sql) {
        throw new UnsupportedOperationException();
    }

    @Override
    public CompletableFuture<QueryResult> asyncQuery(String sql, int maxRecords) {
        throw new UnsupportedOperationException();
    }

    @Override
    public CompletableFuture<QueryResult> asyncQuery(String schema, String sql, int maxRecords) {
        throw new UnsupportedOperationException();
    }

    @Override
    public QueryResult query(String sql) {
        throw new UnsupportedOperationException();
    }

    @Override
    public QueryResult query(String schema, String sql) {
        throw new UnsupportedOperationException();
    }

    @Override
    public QueryResult query(String sql, int maxRecords) {
        throw new UnsupportedOperationException();
    }

    @Override
    public QueryResult query(String schema, String sql, int maxRecords) {
        throw new UnsupportedOperationException();
    }

    @Override
    public long queryCount(String sql, Object... params) {
        throw new UnsupportedOperationException();
    }

    @Override
    public List<Map<String, Object>> queryForList(String sq, Object... params) {
        throw new UnsupportedOperationException();
    }

    @Override
    public Boolean execute(String sql) {
        throw new UnsupportedOperationException();
    }

    @Override
    public Boolean execute(String schema, String sql) {
        throw new UnsupportedOperationException();
    }

    @Override
    public CompletableFuture<Boolean> asyncExecute(String sql) {
        throw new UnsupportedOperationException();
    }

    @Override
    public CompletableFuture<Boolean> asyncExecute(String schema, String sql) {
        throw new UnsupportedOperationException();
    }

    @Override
    public Integer executeUpdate(String sql, Object... params) {
        throw new UnsupportedOperationException();
    }

    @Override
    public Integer executeUpdate(SchemaIdentifier schema, String sql, Object... params) {
        throw new UnsupportedOperationException();
    }

    @Override
    public CompletableFuture<Integer> asyncExecuteUpdate(String sql, Object... params) {
        throw new UnsupportedOperationException();
    }

    @Override
    public CompletableFuture<Integer> asyncExecuteUpdate(SchemaIdentifier schema, String sql, Object... params) {
        throw new UnsupportedOperationException();
    }

    @Override
    public void close() throws Exception {}
}
